package net.haier.fashion.trend.report.config;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.haier.fashion.trend.report.core.common.enums.HttpReturnEnums;
import net.haier.fashion.trend.report.core.common.model.JsonResult;
import net.haier.fashion.trend.report.core.exception.ServiceException;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static net.haier.fashion.trend.report.util.TraceUtil.getTrace;

/**
 * Copyright (C), 2018-2019, 烟台欣和企业食品有限公司
 * fileName ControllerConfig
 *
 * @author 19090005
 * @date 2019/11/20 18:43
 * description
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者名称          修改时间           版本号             描述
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionTranslator {

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> notFountHandler(NoHandlerFoundException ex) {
        String msg = String.format("接口【%s】不存在", ex.getRequestURL());
        log.warn("统一异常 NoHandlerFoundException:{}", msg);
        return ResponseEntity.ok(JsonResult.get(HttpReturnEnums.SYSTEM_ERROR).setCode(HttpStatus.NOT_FOUND.value()).setMsg(msg));
    }

    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(ServiceException ex) {
        String msg = ex.getMessage();
        log.warn("统一异常 ServiceException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(ex.getCode()).setMsg(msg).setData(ex.getData()));
    }


    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(HttpRequestMethodNotSupportedException ex) {
        String msg = ex.getMessage();
        log.warn("统一异常 HttpRequestMethodNotSupportedException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(HttpStatus.METHOD_NOT_ALLOWED.value()).setMsg(msg));
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(MissingServletRequestParameterException ex) {
        String msg = String.format("【%s】不能为空", ex.getParameterName());
        log.warn("统一异常 MissingServletRequestParameterException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(HttpReturnEnums.PARA_ERROR.getValue()).setMsg(msg));
    }


    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        String msg = constraintViolations.stream().map(x -> {
            String template = "【%s】" + x.getMessage();
            return String.format(template, ((PathImpl) x.getPropertyPath()).getLeafNode());
        }).collect(Collectors.joining(StrPool.COMMA));
        log.warn("统一异常 ConstraintViolationException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(HttpReturnEnums.PARA_ERROR.getValue()).setMsg(msg));
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(MethodArgumentTypeMismatchException ex) {
        String msg = String.format("【%s】期望类型为[%s]当前值为:[%s]", ex.getName(), ex.getRequiredType(), ex.getValue());
        log.warn("统一异常 MethodArgumentTypeMismatchException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(HttpReturnEnums.PARA_ERROR.getValue()).setMsg(msg));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(MethodArgumentNotValidException ex) {
        return handleError(ex.getBindingResult());
    }

    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(BindException ex) {
        return handleError(ex.getBindingResult());
    }

    private ResponseEntity<JsonResult<Object>> handleError(BindingResult bindingResult) {
        String msg = bindingResult.getFieldErrors()
                .stream()
                .map(x -> StrUtil.join(StrUtil.EMPTY, StrPool.BRACKET_START, x.getField(), StrPool.BRACKET_END, x.getDefaultMessage()))
                .distinct()
                .collect(Collectors.joining(StrPool.COMMA));
        if (StrUtil.isBlank(msg)) {
            Optional<ObjectError> globalError = Optional.ofNullable(bindingResult.getGlobalError());
            if (globalError.isPresent()) {
                msg = globalError.get().getDefaultMessage();
            }
        }
        log.warn("统一异常 BindException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(HttpStatus.BAD_REQUEST.value()).setMsg(msg));
    }


    @ExceptionHandler(ServletRequestBindingException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(ServletRequestBindingException ex) {
        String msg = ex.getMessage();
        log.warn("统一异常 ServletRequestBindingException:{}", msg);
        return ResponseEntity.ok(JsonResult.ok().setCode(HttpReturnEnums.PARA_ERROR.getValue()).setMsg(msg));
    }

//    @ExceptionHandler(MybatisPlusException.class)
//    @ResponseStatus(HttpStatus.OK)
//    public ResponseEntity<JsonResult<String>> handleError(MybatisPlusException ex) {
//        String msg = ex.getMessage();
//        log.warn("统一异常 MybatisPlusException:{}", msg);
//        return ResponseEntity.ok(JsonResult.<String>ok().setCode(ApiReturnEnums.CHECK_ERROR.value()).setMsg(msg));
//    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<String>> handleError(IllegalArgumentException ex) {
        String msg = ex.getMessage();
        log.warn("统一异常 IllegalArgumentException:{}", msg);
        return ResponseEntity.ok(JsonResult.<String>ok().setCode(HttpReturnEnums.CHECK_ERROR.getValue()).setMsg(msg));
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<String>> handleError(HttpMessageNotReadableException ex) {
        String msg = ex.getMessage();
        log.warn("传参格式错误:{}", msg);
        return ResponseEntity.ok(JsonResult.<String>ok().setCode(HttpReturnEnums.PARA_ERROR.getValue()).setMsg(msg));
    }


    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<JsonResult<Object>> handleError(Exception ex, HttpServletRequest request) {
        try {
            Map<String, Object> trace = getTrace(request);
            String errorMsg = "全局异常参数:" + StrPool.LF + trace.entrySet().stream().map(x -> StrUtil.join(StrUtil.COLON, x.getKey(), x.getValue())).collect(Collectors.joining(StrPool.LF)) + StrPool.LF + "内容:" + StrPool.LF;
            log.error(errorMsg, ex);
        } catch (Exception e) {
            log.error("全局异常:", ex);
        }
        JsonResult<Object> result = JsonResult.get(HttpReturnEnums.SYSTEM_ERROR);
        return ResponseEntity.ok(result);
    }


}
